package model;

import java.util.*;

import com.googlecode.objectify.*;
import com.googlecode.objectify.util.DAOBase;

import com.javadocmd.simplelatlng.*;
import com.javadocmd.simplelatlng.util.*;

import java.util.logging.Logger;

// Data Access Object
public class DAO extends DAOBase{
	private static final Logger log = Logger.getLogger(DAO.class.getName());
	
	static {
		ObjectifyService.register(UserProfile.class);
		ObjectifyService.register(EventInfo.class);		
		ObjectifyService.register(EventMsg.class);		
		ObjectifyService.register(EventPlus.class);
		ObjectifyService.register(EventLike.class);
		ObjectifyService.register(EventUser.class);
		// .... 
	}

	private double calDistance(double x1, double y1, double x2, double y2) {
		LatLng point1 = new LatLng(x1, y1);
		LatLng point2 = new LatLng(x2, y2);
		double distance = LatLngTool.distance(point1, point2, LengthUnit.METER);
		return distance;
	}
	
	
	public UserProfile getOrCreateUserProfile(String email, String fbid, String name,
			String gender) 
	{
		UserProfile found = ofy().find(UserProfile.class, email);
		if (found == null)			
			return new UserProfile(email, fbid, name, gender);
		else
			return found;
	}

	public EventInfo getEventInfoById(long eid) {
		return ofy().find(EventInfo.class, eid);
	}
	
	public EventInfo createEventInfo(String uid, int type, String name, String brief,
			Date deadline,int limitCount, double x, double y,
			double user_x, double user_y, String place) {
			return new EventInfo( uid, type, name, brief, deadline, limitCount, x, y,
					user_x, user_y, place);
	}
	
	public List<EventInfo> getEventsList() {
		Query<EventInfo> q = ofy().query(EventInfo.class).filter("status.estatus =", 1);
		List<EventInfo> list = new ArrayList<EventInfo>();
		for (EventInfo ei: q) {
			list.add(ei);
		}
		return list;
	}
	
	public List<EventInfo> getNearEventList(String uid, double range, boolean isPast) {
		Date d = new Date();
		//log.warning("Scan Date = "+ d);
		Query<EventInfo> q;
		if(isPast)
			q = ofy().query(EventInfo.class).filter("deadline <=", d);
		else
			q = ofy().query(EventInfo.class).filter("deadline >", d);
		
		List<EventInfo> list = new ArrayList<EventInfo>();
		UserProfile up = getUserProfileById(uid);
		
		double x1 = up.status.getX();
		double y1 = up.status.getY();
		
		//log.warning("Range = "+ range);
		
		for (EventInfo ei: q) {
			double x2 = ei.status.x;
			double y2 = ei.status.y;
			double dis = calDistance(x1,y1,x2,y2);
			//log.warning("DIS = "+ dis);
			if(dis < range)
				list.add(ei);
		}
		return list;
	}
	
	public List<EventInfo> getMyCreateEventList(String uid) {
		Query<EventInfo> q;
		q = ofy().query(EventInfo.class).filter("uid =", uid);
		List<EventInfo> list = q.list();
		return list;
	}

	public List<EventInfo> getMyPlusEventList(String uid) {
		Query<EventPlus> q;
		Key<UserProfile> k = new Key<UserProfile>(UserProfile.class, uid);
		q = ofy().query(EventPlus.class).filter("user =", k);		
		List<EventInfo> list = new ArrayList<EventInfo>();
		for (EventPlus ep: q) {
			EventInfo ei = ofy().get(ep.getEvent());
			list.add(ei);
		}
		return list;		
	}
	
	
	public EventPlus createEventPlus(long eid, String uid) {
			return new EventPlus(eid, uid);
	}
	
	public List<UserProfile> getPlusUser(long eid) {
		EventInfo ei = getEventInfoById(eid);		
		Query<EventPlus> q = ofy().query(EventPlus.class).filter("event", ei);
		List<UserProfile> list = new ArrayList<UserProfile>();
		for (EventPlus ep: q) {
			UserProfile user = ofy().get(ep.user);
			list.add(user);
		}
		return list;
	}
	
	public ChatPlus createChatPlus(String fromUid, String toUid) {
		return new ChatPlus(fromUid, toUid);
	}
	
	public UserProfile getUserProfileById(String uid) {
		return ofy().get(UserProfile.class, uid);
	}
	
	public UserProfile getUserProfileByFBId(String fbid) {		
		Query<UserProfile> q = ofy().query(UserProfile.class).filter("fbid =", fbid);
		return q.get();
	}
	
	public void updateEventUseCount(long eid, boolean isInc)
	{
		Objectify ofy = ObjectifyService.beginTransaction();
		try{
			Key<EventInfo> eventKey = new Key<EventInfo>(EventInfo.class, eid);
			EventInfo ei = ofy().get(eventKey);
			if(isInc)
				ei.incUseCount();
			else
				ei.desUseCount();
			ofy.put(ei);
			ofy.getTxn().commit();
		}
		finally {
			if (ofy.getTxn().isActive())
				ofy.getTxn().rollback();
		}
	}
	
	public void incEventPlusCount(long eid)
	{
		Objectify ofy = ObjectifyService.beginTransaction();
		try{
			Key<EventInfo> eventKey = new Key<EventInfo>(EventInfo.class, eid);
			EventInfo ei = ofy().get(eventKey);
			ei.incPlusCount();
			ofy.put(ei);
			ofy.getTxn().commit();
		}
		finally {
			if (ofy.getTxn().isActive())
				ofy.getTxn().rollback();
		}
	}

	public void incEventLikeCount(long eid)
	{
		Objectify ofy = ObjectifyService.beginTransaction();
		try{
			Key<EventInfo> eventKey = new Key<EventInfo>(EventInfo.class, eid);
			EventInfo ei = ofy().get(eventKey);
			ei.incLikeCount();
			ofy.put(ei);
			ofy.getTxn().commit();
		}
		finally {
			if (ofy.getTxn().isActive())
				ofy.getTxn().rollback();
		}
	}
	
	public String getUserJid(String uid)
	{
		Key<UserProfile> userKey = new Key<UserProfile>(UserProfile.class, uid);
		UserProfile up = ofy().get(userKey);
		return up.getJid();
	}

	public List<String> getEventJidList(long eid)
	{
		Key<EventInfo> eventKey = new Key<EventInfo>(EventInfo.class, eid);
		Query<EventUser> q = ofy().query(EventUser.class).filter("event =", eventKey);
		
		List<String> list = new ArrayList<String>();
		for (EventUser eu: q) {			
			list.add(eu.getJid());
		}				
		return list;
	}

	
	//EventUser
	public void deleteEventUser(long eid, String uid)
	{
		Key<EventInfo> eventKey = new Key<EventInfo>(EventInfo.class, eid);
		Key<UserProfile> userKey = new Key<UserProfile>(UserProfile.class, uid);
		Query<EventUser> q = ofy().query(EventUser.class).filter("event =", eventKey)
				.filter("user", userKey);
		Iterable<Key<EventUser>> allKeys = q.fetchKeys();
		ofy().delete(allKeys);
	}
	
	public boolean checkEventUser(long eid, String uid) {
		Key<EventInfo> eventKey = new Key<EventInfo>(EventInfo.class, eid);
		Key<UserProfile> userKey = new Key<UserProfile>(UserProfile.class, uid);
		Query<EventUser> q = ofy().query(EventUser.class).filter("event =", eventKey)
				.filter("user =", userKey);
		
		Key<EventUser> eukey = q.getKey();
		if(eukey == null)
			return true;
		else
			return false;			
	}
	
	public List<UserProfile> getEventUser(long eid) {
		Key<EventInfo> eventKey = new Key<EventInfo>(EventInfo.class, eid);
		Query<EventUser> q = ofy().query(EventUser.class).filter("event =", eventKey);
		
		List<UserProfile> list = new ArrayList<UserProfile>();
		for (EventUser eu: q) {
			UserProfile up = ofy().get(eu.getUser());
			list.add(up);
		}		
		return list;
	}
	
	//EventMsg
	public List<EventMsg> getEventMsg(long eid) {
		Key<EventInfo> eventKey = new Key<EventInfo>(EventInfo.class, eid);
		Query<EventMsg> q = ofy().query(EventMsg.class).filter("event =", eventKey);
		
		List<EventMsg> list = new ArrayList<EventMsg>();
		for (EventMsg eu: q) {
			UserProfile up = ofy().get(eu.getUser());
			eu.setUsername(up.getName());
			list.add(eu);
		}		
		return list;
	}
	
	//EventPlus
	public List<UserProfile> getEventPlus(long eid) {
		Key<EventInfo> eventKey = new Key<EventInfo>(EventInfo.class, eid);
		Query<EventPlus> q = ofy().query(EventPlus.class).filter("event =", eventKey);
		
		List<UserProfile> list = new ArrayList<UserProfile>();
		for (EventPlus ep: q) {
			UserProfile up = ofy().get(ep.getUser());
			list.add(up);
		}		
		return list;
	}
	
	//EventLike
	public List<UserProfile> getEventLike(long eid) {
		Key<EventInfo> eventKey = new Key<EventInfo>(EventInfo.class, eid);
		Query<EventLike> q = ofy().query(EventLike.class).filter("event =", eventKey);
		
		List<UserProfile> list = new ArrayList<UserProfile>();
		for (EventLike el: q) {
			UserProfile up = ofy().get(el.getUser());
			list.add(up);
		}		
		return list;
	}
	
}
